package cn.biplam.front.component.view.systemManage.menu;

import java.util.ArrayList;

import cn.biplam.common.client.DbResource;
import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.KvMap;
import cn.biplam.common.wrapper.UserInfo;
import cn.biplam.front.component.AjxResponse;
import cn.biplam.front.component.view.systemManage.menu.thirdTree.DataDealRuleTree;
import cn.biplam.front.component.view.systemManage.menu.thirdTree.ModelRuleTree;
import cn.biplam.front.component.view.systemManage.menu.thirdTree.SqlRuleTree;
import cn.biplam.front.component.view.systemManage.menu.thirdTree.SystemRuleTree;
import cn.biplam.front.html.HtmlDiv;
import cn.biplam.front.html.base.HtmlWindow;
import cn.biplam.front.template.control.Tree;

/**
 * 三级菜单导航树
 *   显示三级菜单的导航树
 *   nodeId格式为pcId+actionId,nodeId,operatorType,nodeType,nodeLevel,是否有哥哥,弟弟,realId,父亲们是否有弟弟
 *   <p>MenuTreeThird tree = new MenuTreeThird(),【必选】,初始化业务模型导航对象<p><br>
 *   <p>tree.setFilter(Menu_Type.Dw),【可选】,设置三级菜单过滤器,默认显示全部业务模型对象<p><br>
 *   <p>tree.setModelCallBack(),【可选】,设置三级菜单左键信息,不设置默认无左键<p><br>
 *   <p>tree.setRightMenu(true),【可选】,设置树的右键,默认显示右键<p><br>
 *   <p>tree.setShowCheckBox(true),【可选】,设置复选框,默认不显示复选框<p><br>
 *   <p>tree.setExtendNodeID("1011")【可选】,设置需要展开的节点id<p>
 *   <p>tree.get()【必选】,取树的信息<p><br>
 * @author WangSong 2009-6-8下午04:23:40
 * @version 1.0
 */
public class MenuTreeThird extends AjxResponse {

	public static final String cId="1011";
	/**树调用的actionId */
	public static final String aId="101101";
	/**父容器id */
	private String pcId;
	/**显示的dc，设置过滤器时初始化 */
	private KvMap<Integer,String> showObject;
	/**指定显示的dc的参数设置 ，设置过滤器时初始化*/
	private KvMap<String,KvMap<String,String>> showObjectParam;
	/**显示的dc计数器 */
	private int icount;
	/**当前节点id */
	private String nodeId;
	/**向下取几级节点 */
	private String levelDown;
	/**当前节点级别 */
	private String nodeLevel;
	/**节点所属对象类型 */
	private int nodeType;
	/**父亲们是否有弟弟 */
	private String parentsHaveLBrother;
	/**树 */
	private HtmlWindow tree;
	/**TreeData集合 Object[0]:TreeData , Object[1]:TreeCallBack */
	private ArrayList<Object[]> alTreeData;
	/**对象类型和回调函数的映射 */
	private KvMap<Menu_Type,String[]> kvCallBack;
	/**是否显示右键菜单 */
	private boolean showRightMenu = true;
	/**是否显示复选框 */
	private boolean showCheckBox = false;
	/**展开的节点id */
	private String extendNodeId;
	/**是否显示加号减号 */
	private boolean showPicExtend = false;
	/**当前节点是否有哥哥 */
	private String haveBrother;
	/**当前节点是否有弟弟 */
	private String haveLBrother;

	public enum Menu_Type{

		/**系统维护规则 */
		System("1"),
		/**SQL引擎规则 */
		SQL("2"),
		/**业务模型规则 */
		BusinessModel("3"),
		/**数据处理规则 */
		DataDeal("4");

		private String value;
		private Menu_Type(String value){this.value=value;}
		public String toString() {return value;}
	}

	public MenuTreeThird(){
		//初始化ModelTree默认参数：节点Id、节点级别、向下取树的几级
		this.nodeId = "-1";
		this.nodeLevel = "0";
		this.levelDown = "1";
		this.parentsHaveLBrother = null;
		this.kvCallBack = new KvMap<Menu_Type,String[]>();
		this.alTreeData = new ArrayList<Object[]>();
		this.tree = new HtmlDiv();
	}

	/**
	 * 页面直接调用接口(用于非Ajx请求时,获取页面对象)
	 *  第一次生成业务模型树时调用
	 *  没设置过滤器(此时nodeId,nodeLevel,levelDown为系统指定参数,不可更改)
	           nodeId:-1,nodeLevel:1,levelDown:1,nodeType:DC自己设置
	      设置了过滤器(此时nodeId,nodeLevel,levelDown参数可以随过滤器一起指定)
	 * @param user    用户信息
	 * @param homeUrl 系统信息
	 * @param cId     调用者的容器id
	 */
	public HtmlWindow get(UserInfo user, String homeUrl,String pcId) throws ErrorMessage {
		this.mUser = user;
		this.sHomeUrl = homeUrl;
		this.pcId = pcId;
		//获取树的节点页面信息;
		this.getTree();
		return this.tree;
	}

	/**
	 * 上层容器ajx调用时的调用接口
	 * @param user     用户信息
	 * @param homeUrl
	 * @param params   ajx的参数
	 * @return HtmlWindow
	 * @throws ErrorMessage
	 */
	private HtmlWindow get(UserInfo user, String homeUrl,KvMap<String,String> params) throws ErrorMessage{
		this.mUser = user;
		this.sHomeUrl = homeUrl;
		this.params = params;
		//为getTree准备所需的数据(userId,nodeId,nodeLevel,levelDown,nodeType)从ajx的params中取
		this.setParamAjx();
		//设置过滤器、左键、右键、复选框、需要展开节点等信息
		this._setAjxInfo();
		getTree();
		return tree;
	}

	/**
	 * 用于Ajx请求时,获取页面对象
	 */
	@Override
	public HtmlWindow ajxGet() throws ErrorMessage {
		
		if("Y".equals(this.params.getByKey("refresh"))){//树的增删改刷新
			this._setRefreshParam();
			getTree();
			return tree;
		}else{
			return this.get(this.mUser,this.sHomeUrl, this.params);	
		}

	}

	/**
	 * 取树节点信息
	 * @throws ErrorMessage
	 */
	@SuppressWarnings("static-access")
	private void getTree() throws ErrorMessage{

		/**根据dc取树的TreeData。第一次生成树节点时用get()，TreeData是根据过滤器的设置来取。
		     以后树节点的展开是用ajxGet(), 此时TreeData是根据节点的属性来判断用哪个Dc,然后设置过滤器*/
		this.setTreeDatas();

		//初始化树的模版
		Tree mTree = new Tree(this.pcId,
				this.aId,
				this.alTreeData,
				this.sHomeUrl);
		//设置是否显示右键菜单
		if(this.showRightMenu){
			this._setRightMenu(mTree);
		}
		//设置是否显示复选框
		mTree.setCheckBox(showCheckBox);
		//设置展开节点Id
		if(this.extendNodeId!=null){
			mTree.setExtendNodeId(this.extendNodeId);
		}
		mTree.showPicExtend(showPicExtend);
		this.tree = mTree.get();
	}

	/**
	 * ajx的树请求设置过滤器
	 * @throws ErrorMessage
	 */
	private void _setAjxInfo() throws ErrorMessage{
		//根据业务模型对象大的类型，取业务模型对象的枚举字符串
		Menu_Type modelType = this._getModleType(this.nodeType);
		//设置过滤器
		this.setFilter(modelType, nodeId, nodeLevel, levelDown);
		//设置左键容器id，左键目标id、是否显示右键、是否显示checkBox信息
		this.setModelCallBack(modelType, this.params.getByKey("tId"), this.params.getByKey("aId"));
		//设置右键是否显示
		this.showRightMenu = Boolean.parseBoolean(this.params.getByKey("srm"));
		//设置是否显示复选框
		this.showCheckBox = Boolean.parseBoolean(this.params.getByKey("sck"));
	}

	/**
	 * 根据业务模型对象大的类型，取业务模型对象的枚举字符串
	 * @return objectValue
	 * @throws ErrorMessage 
	 */
	private Menu_Type _getModleType(int nodeType) throws ErrorMessage{
		String objectValue = null;
		switch(nodeType){
		case 1://系统维护规则
			objectValue = "System";
			break;
		case 2://SQL引擎规则
			objectValue = "SQL";
			break;
		case 3://业务模型规则
			objectValue = "BusinessModel";
			break;
		case 4://数据处理规则
			objectValue = "DataDeal";
			break;
		default:
			throw new ErrorMessage("MenuTreeThird nodeType not found:"+nodeType);
		}
		return Menu_Type.valueOf(objectValue);
	}


	/**
	 * 设置树的数据信息
	 * @throws ErrorMessage 
	 */
	private void setTreeDatas() throws ErrorMessage{
		//从DC中取出需要的treeData和callBack,放到ArrayList<Object[]>中，设置到树的模版中
		if(this.showObject!=null){//显示设置的dc
			this.showDc();
		}else{//显示全部dc
			showDcSwitch(1);
			showDcSwitch(2);
			showDcSwitch(3);
			showDcSwitch(4);
		}
	}

	/**
	 * 显示已经设置的dc
	 * @throws ErrorMessage 
	 */
	private void showDc() throws ErrorMessage{
		int showParam;
		for(int i=0;i<this.showObject.size();i++){
			showParam = TOOLS.stringToInt(this.showObject.getByKey(i));
			this.showDcSwitch(showParam);
		}
	}

	private void showDcSwitch(int showParam) throws ErrorMessage{
		//根据设置的DC的参数来初始化nodeId, nodeLevel, levelDown, showCurrentNode等信息
		Object[] obj = new Object[2];
		String nodeId = this.getSetFilterParam(TOOLS.intToString(showParam), "nodeId", this.nodeId);
		String nodeLevel = this.getSetFilterParam(TOOLS.intToString(showParam), "nodeLevel", this.nodeLevel);
		String levelDown = this.getSetFilterParam(TOOLS.intToString(showParam), "levelDown", this.levelDown);
		String parentsHaveLBrother = this.getSetFilterParam(TOOLS.intToString(showParam), "parentsHaveLBrother", this.parentsHaveLBrother);
		switch(showParam){
		case 1://系统维护规则
			obj[0] = new SystemRuleTree(this.mUser,this.sHomeUrl).getTreeData(mUser.getUserID(),
                    nodeId,
                    nodeLevel, 
                    levelDown,
                    haveBrother,
                    haveLBrother,
                    parentsHaveLBrother,
                    new DbResource());
			obj[1] = new SystemRuleTree(this.mUser,this.sHomeUrl)
			.getCallBack(_getCallBackSet(Menu_Type.System)[0],
					_getCallBackSet(Menu_Type.System)[1]);
			break;
		case 2://SQL引擎规则
			obj[0] = new SqlRuleTree(this.mUser,this.sHomeUrl).getTreeData(mUser.getUserID(),
                    nodeId,
                    nodeLevel, 
                    levelDown,
                    haveBrother,
                    haveLBrother,
                    parentsHaveLBrother,
                    new DbResource());
			obj[1] = new SqlRuleTree(this.mUser,this.sHomeUrl)
			.getCallBack(_getCallBackSet(Menu_Type.SQL)[0],
					_getCallBackSet(Menu_Type.SQL)[1]); 
			break;
		case 3://业务模型规则
			obj[0] = new ModelRuleTree(this.mUser,this.sHomeUrl).getTreeData(mUser.getUserID(),
                    nodeId,
                    nodeLevel, 
                    levelDown,
                    haveBrother,
                    haveLBrother,
                    parentsHaveLBrother,
                    new DbResource());
			obj[1] = new ModelRuleTree(this.mUser,this.sHomeUrl)
			.getCallBack(_getCallBackSet(Menu_Type.BusinessModel)[0],
					_getCallBackSet(Menu_Type.BusinessModel)[1]); 
			break;
		case 4://数据处理规则
			obj[0] = new DataDealRuleTree(this.mUser,this.sHomeUrl).getTreeData(mUser.getUserID(),
                    nodeId,
                    nodeLevel, 
                    levelDown,
                    haveBrother,
                    haveLBrother,
                    parentsHaveLBrother,
                    new DbResource());
			obj[1] = new DataDealRuleTree(this.mUser,this.sHomeUrl)
			.getCallBack(_getCallBackSet(Menu_Type.DataDeal)[0],
					_getCallBackSet(Menu_Type.DataDeal)[1]); 
			break;
		default:
			throw new ErrorMessage("MenuTreeThird enum Show_Object not found:"+showParam);
		}
		if(obj[1]==null){
			throw new ErrorMessage("MenuTreeThird.java SrcTree TreeCallBack is null");
		}
		this.alTreeData.add(obj);
	}

	/**
	 * 取回调函数的参数设置，如果没设置参数，则默认用"";
	 * @param modelType
	 * @return
	 */
	private String[] _getCallBackSet(Menu_Type modelType){
		String[] callBackParam = new String[2];
		if(this.kvCallBack.getByKey(modelType)!=null){
			callBackParam = this.kvCallBack.getByKey(modelType);
		}else{
			callBackParam[0]="";
			callBackParam[1]="";
		}
		return callBackParam;
	}

	/**
	 * 取得设置过滤器时设置的参数信息，如果没有在设置过滤器时设置此参数，则用默认值
	 * @param modelType  业务对象模型类型
	 * @param paramName  参数名称
	 * @param defaultValue  参数默认值
	 * @return String
	 * @throws ErrorMessage 
	 */
	private String getSetFilterParam(String modelType,String paramName,String defaultValue) throws ErrorMessage{
		String paramValue = null;

		if(this.showObjectParam!=null){
			//取参数集合
			KvMap<String,String> params = this.showObjectParam.getByKey(modelType);
			if(params!=null){
				//取指定参数
				paramValue = params.getByKey(paramName);
			}
		}

		//如果没有在设置过滤器时设置此参数，则用默认值
		if(paramValue == null || "".equals(paramValue.trim())){
			paramValue = defaultValue;
		}
		return paramValue;
	}

	/**
	 * 设置显示哪些DC,如果不设置则不进行过滤，全部显示。如果设置显示的DC则按照设置的DC项显示
	 * @throws ErrorMessage 
	 */
	public void setFilter(Menu_Type showDc) throws ErrorMessage{
		//在VC中增加DC的过滤器，选择显示哪些DC
		if(this.showObject==null){
			this.showObject = new KvMap<Integer,String>();
		}
		this.showObject.put(this.icount,showDc.toString());
		this.icount++;
	}

	/**
	 * 设置显示哪些DC,如果不设置则不进行过滤，全部显示。如果设置显示的DC则按照设置的DC项显示
	 * @param showDc       显示的DC
	 * @param nodeId       节点id
	 * @param nodeLevel    节点级别
	 * @param levelDown    
	 * @param showCurrentNode
	 * @throws ErrorMessage
	 */
	public void setFilter(Menu_Type showDc,
			String nodeId,
			String nodeLevel,
			String levelDown) throws ErrorMessage{
		if(this.showObjectParam==null){
			this.showObjectParam = new KvMap<String, KvMap<String,String>>();
		}
		KvMap<String,String> kvParam = new KvMap<String, String>();
		this.setParam(kvParam, "nodeId",nodeId);
		this.setParam(kvParam, "nodeLevel",nodeLevel);
		this.setParam(kvParam, "levelDown",levelDown);
		this.setFilter(showDc);
		this.showObjectParam.put(showDc.toString(), kvParam);
	}


	/**
	 * 设置参数，如果参数不为空则设置参数
	 * @param kvParam
	 * @param param
	 * @param paramValue
	 * @throws ErrorMessage
	 */
	private void setParam(KvMap<String,String> kvParam,
			String param,
			String paramValue) throws ErrorMessage{
		if(paramValue!=null && !paramValue.equals("")){
			kvParam.put(param, paramValue);
		}
	}

	/**
	 * 设置右键菜单（右键菜单的设置，放在了各个DC当中，是否显示右键菜单在Vc中控制，由Vc调用DC来设置树的右键菜单）
	 * @param mTree
	 * @throws ErrorMessage 
	 */
	private void _setRightMenu(Tree mTree) throws ErrorMessage{
		//是否设置了过滤器
		if(this.showObject!=null){
			//设置了过滤器，设置过滤器中的业务对象模型右键菜单
			for(int i=0;i<this.showObject.size();i++){
				setDCRightMenu(TOOLS.stringToInt(this.showObject.getByKey(i)),mTree);
			}
		}else{
			//没设置过滤器，设置所有业务对象模型右键菜单
			setDCRightMenu(1,mTree);
			setDCRightMenu(2,mTree);
			setDCRightMenu(3,mTree);
			setDCRightMenu(4,mTree);
		}
	}

	/**
	 * 设置右键菜单
	 * @param dcType   业务模型对象类型
	 * @param mTree    树的模版对象
	 * @throws ErrorMessage
	 */
	private void setDCRightMenu(int dcType,Tree mTree) throws ErrorMessage{
		switch(dcType){
		case 1://系统维护规则
			new SystemRuleTree(this.mUser,this.sHomeUrl).setRightMenu(mTree);
			break;
		case 2://SQL引擎规则
			new SqlRuleTree(this.mUser,this.sHomeUrl).setRightMenu(mTree);
			break;
		case 3://业务模型规则
			new ModelRuleTree(this.mUser,this.sHomeUrl).setRightMenu(mTree);
			break;
		case 4://数据处理规则
			new DataDealRuleTree(this.mUser,this.sHomeUrl).setRightMenu(mTree);
			break;
		default:
			throw new ErrorMessage("ModelTree enum Show_Object not found:"+dcType);
		}
	}

	/**
	 * ajx请求时，从params中取页面传来的参数
	 * @throws ErrorMessage 
	 */
	private void setParamAjx() throws ErrorMessage{
		//nodeId格式为cId,nodeId,operatorType,nodeType,nodeLevel,是否有哥哥,弟弟,父亲们是否有弟弟
		String [] nodeIdParams = this.splitParam(this.params.getByKey("nodeId"));
		this.nodeId = nodeIdParams[1];
		this.nodeLevel = nodeIdParams[4];
		//通过ajx来取树,是展开节点取当前节点的下级,此时只向下取一级
		this.levelDown = "1";
		if(nodeIdParams.length<9){//根节点的次参数是空的
			this.parentsHaveLBrother = null;
		}else{
			this.parentsHaveLBrother = nodeIdParams[8];
		}
		this.pcId = nodeIdParams[0].substring(0,4);
		//用于判断节点是哪个业务模型对象类型，从而取相应的TreeData
		this.nodeType = TOOLS.stringToInt(nodeIdParams[2]);
		//需要展开的节点id
		this.extendNodeId = this.params.getByKey("extendId");
		this.haveBrother = nodeIdParams[5];
		this.haveLBrother = nodeIdParams[6];
	}

	/**
	 * 分解参数信息
	 * @param params
	 * @return String[]
	 * @throws ErrorMessage
	 */
	private String[] splitParam(String params) throws ErrorMessage{
		if(params==null || "".equals(params.trim())){
			throw new ErrorMessage("【Error】ModelTree.java  params is null");
		}
		String [] nodeIdParams = params.split("#");
		if(nodeIdParams.length<7){
			throw new ErrorMessage("【Error】ModelTree.java  params is not correct:"+params);
		}
		return nodeIdParams;
	}

	/**
	 * 设置树的刷新时的参数准备
	 * @throws ErrorMessage 
	 */
	private void _setRefreshParam() throws ErrorMessage{
		this.pcId = this.params.getByKey("pcid");
		//设置过滤器
		this._setRefreshFilter();
		//设置是否显示右键
		this._setRefreshShowRightMenu();
		//设置是否显示checkBox
		this._setRefreshShowCheckBox();
		//设置callback
		this._setRefreshCallBack();
		//设置展开节点
		this._setsetRefreshExtendNode();
	}

	/**
	 * 设置树刷新时的过滤器信息
	 * @throws ErrorMessage 
	 */
	private void _setRefreshFilter() throws ErrorMessage{
		String filter = this.params.getByKey("filter");
		if(filter!=null){
			//分割多个过滤器
			String[] arrFilters = filter.split("_");
			String[] arrFilter = null;
			for(int i=0;i<arrFilters.length;i++){
				arrFilter = arrFilters[i].split(":");
				if(arrFilter.length >= 2){
					this.setFilter(this._getModleType(TOOLS.stringToInt(arrFilter[0])),
							arrFilter[1], nodeLevel, levelDown);
				}
			}
		}
	}

	/**
	 * 设置树刷新时的左键信息
	 * @throws ErrorMessage 
	 */
	private void _setRefreshCallBack() throws ErrorMessage{
		if(this.params.getByKey("callback")!=null){
			//分割过个callback
			String[] arrCallbacks = this.params.getByKey("callback").split("_");
			String[] arrcallback = null;
			for(int i=0;i<arrCallbacks.length;i++){
				arrcallback = arrCallbacks[i].split(":");
				if(arrcallback.length == 3){
					this.setModelCallBack(this._getModleType(TOOLS.stringToInt(arrcallback[0])),
							arrcallback[1], 
							arrcallback[2]);
				}
			}
		}
	}

	/**
	 * 设置树刷新时是否显示右键
	 * @throws ErrorMessage 
	 */
	private void _setRefreshShowRightMenu() throws ErrorMessage{
		if(this.params.getByKey("srm")!=null){
			this.showRightMenu = Boolean.parseBoolean(this.params.getByKey("srm"));
		}
	}

	/**
	 * 设置树刷新时是否显示复选框
	 */
	private void _setRefreshShowCheckBox(){
		if(this.params.getByKey("srm")!=null){
			this.showCheckBox = Boolean.parseBoolean(this.params.getByKey("sck"));
		}
	}

	/**
	 * 设置树刷新时需要展开的节点
	 * @throws ErrorMessage 
	 */
	private void _setsetRefreshExtendNode() throws ErrorMessage{
		if(this.params.getByKey("extendId")!=null){
			this.extendNodeId = this.params.getByKey("extendId");
		}else{
			throw new ErrorMessage("【Error】MenuTreeThird.java,when refresh the tree ,extendNodeId is null!");
		}
	}

	/**
	 * 设置业务模型对象的回调函数
	 * @param modelType  业务模型对象类型
	 * @param tcb        回调函数对象
	 * @throws ErrorMessage
	 */
	public void setModelCallBack(Menu_Type modelType,
			String target,
			String actionId) throws ErrorMessage{
		String[] param = new String[2];
		param[0] = target;
		param[1] = actionId;
		this.kvCallBack.put(modelType, param);
	}

	/**
	 * 设置右键菜单是否显示
	 * @param show  true显示 false不显示
	 */
	public void setRightMenu(boolean show){
		this.showRightMenu = show;
	}

	/**
	 * 设置是否显示复选框
	 * @param show
	 */
	public void setShowCheckBox(boolean show){
		this.showCheckBox = show;
	}

	/**
	 * 设置需要展开的节点的Id
	 * @param extendNodeId 需要展开的节点Id
	 */
	public void setExtendNodeID(String extendNodeId,String extendNodeLevel){
		this.extendNodeId = extendNodeId;
	}

	/**
	 * 是否显示加号减号
	 * @param showPicExtend
	 */
	public void showPicExtend(boolean showPicExtend){
		this.showPicExtend = showPicExtend;
	}

}
